package com.hup.joystick.service.joyEvent;

import com.hup.joystick.model.FunctionConfig;
import com.hup.joystick.model.FunctionConfig.FunctionItem;
import com.hup.joystick.model.joystick.StandardEvent;
import com.hup.joystick.model.joystick.StandardEvent.StandardAction;
import com.hup.joystick.model.joystick.StandardKey;
import com.hup.utils.commons.ListUtil;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * @author hugan
 * @date 2020/11/1
 */
public interface IJoyEventHandler {

    /**
     * 释放所有激活的功能,调用者:
     * .产生错误(断开设备,其他错误)后
     * .handlePressAndConsume拦截事件后
     */
    void releaseAllActiveFunction();

    /**
     * 处理[抬起事件]
     *
     * @param standardKey 按下的按键
     */
    void handleRelease(StandardEvent e, StandardKey standardKey);

    /**
     * 实现业务功能后终止[按下事件]的传递;
     * .调用{@link #handlePress(ArrayList, ArrayList, FunctionConfig)}的方法
     * .一般是handlePressAndConsume,handlePress二选一进行重写,实现业务方法
     *
     * @return consumed:true-终止事件传递
     */
    default boolean handlePressAndConsume(StandardEvent e, ArrayList<StandardAction> newPress,
            FunctionConfig matchConfig) {
        return false;
    }

    /**
     * 处理[按下事件]
     * .处理未处理的[新按下事件]
     * .处理[当前所有按下中的事件]
     *
     * @param newPress emptyAble,当前 {@link StandardEvent} 中,未处理的[新按下事件];调用本方法后,已处理事件将从列表中被移除
     * @param currentPress 当前 {@link StandardEvent} 中,所有在按下的按键
     * @param matchConfig 符合要求的配置(生效的,符合生效程序的,合并后的)
     * @apiNote 调用时, 遍历[处理器]调用, newPress为空时也不能终止传递, 因为[如鼠标移动]是要每次都使用currentPress的
     */
    void handlePress(ArrayList<StandardAction> newPress, ArrayList<StandardAction> currentPress,
            FunctionConfig matchConfig);

    /**
     * 处理[新抬起事件],释放已激活的功能:
     * .遍历所有当前已激活的功能,只要功能包含本次[抬起事件的key],则释放这个功能
     * .匹配到功能后,会将功能从lstActive移除
     *
     * @param standardKey 新抬起事件的按键
     * @param lstActive 已激活的功能
     * @param releaser 释放功能执行器
     */
    static void matchReleaseBtnFunction(StandardKey standardKey, ArrayList<FunctionItem> lstActive,
            Consumer<FunctionItem> releaser) {
        for (Iterator<FunctionItem> it = lstActive.iterator(); it.hasNext(); ) {
            FunctionItem function = it.next();
            if (function.lstStandardKey.contains(standardKey.key)) {
                it.remove();
                releaser.accept(function);
                //找到后不能break,要继续遍历其他功能
            }
        }
    }

    /**
     * 根据[新按下事件],寻找符合的功能
     *
     * @param newPress 新按下事件
     * @param currentPress 当前 {@link StandardEvent} 中,所有在按下的按键
     * @param config 配置
     * @return nullable, 当前按下事件可以激活的功能
     */
    static FunctionItem matchPressBtnFunction(StandardAction newPress, ArrayList<StandardAction> currentPress,
            FunctionConfig config, Predicate<FunctionItem> functionFilter) {
        String currentPressedKey = newPress.standardKey.key;//本次按下的标准按键
        for (FunctionItem function : config.lstFunction) {
            if (!functionFilter.test(function)) continue;
            //本功能不含当前按键:匹配本配置的下一个功能;必须有这句判断本次事件是这个功能的,才开始匹配[currentPress]
            if (!function.lstStandardKey.contains(currentPressedKey)) continue;

            if (function.lstStandardKey.size() != 1) {
                /*
                1个标准按键:contains已经匹配成功了;
                多个标准按键:要从[currentPress]中找到所有要按下的按键
                 */
                boolean notMatch = false;
                for (String needPress : function.lstStandardKey) {
                    if (needPress.equals(currentPressedKey)) continue;//跳过本次事件按下的按键
                    StandardAction found = ListUtil.get(currentPress, press -> press.standardKey.key.equals(needPress));
                    if (found == null) {
                        notMatch = true;//没找到要按下的[标准按键]
                        break;
                    }
                }
                if (notMatch) continue;//匹配本配置的下一个功能
            }
            //激活的功能
            return function;
        }
        return null;
    }

}
